//! Control flow expression parsing (if, for, while, try, block, match, select, go)

use super::patterns::*;
use super::Parser;
use crate::ast::expr::*;
use crate::error::{CompilerError, Result};
use crate::lexer::token::Token;

/// Parse block expression (Rust-style: last expression is the return value)
/// { stmt1; stmt2; expr } returns expr
pub fn parse_block_expression(parser: &mut Parser) -> Result<Option<Expression>> {
    parser.expect(&Token::LeftBrace)?;

    let mut statements = Vec::new();
    let mut result_expr: Option<Expression> = None;

    while !parser.check(&Token::RightBrace) {
        // Skip any semicolons
        while parser.consume(&Token::Semicolon)? {}

        if parser.check(&Token::RightBrace) {
            break;
        }

        // Try to parse as expression first
        if let Some(expr) = super::parse_expression(parser)? {
            // Check if this is the last expression (no semicolon follows)
            if parser.check(&Token::RightBrace) {
                // This is the final expression, it's the return value
                result_expr = Some(expr);
                break;
            } else if parser.consume(&Token::Semicolon)? || parser.check(&Token::RightBrace) {
                // Expression followed by semicolon or end of block
                // Convert to expression statement
                statements.push(crate::ast::stmt::Statement::Expression(expr));
            } else {
                // No semicolon and not end of block - error
                return Err(CompilerError::syntax(
                    parser.current_location().line,
                    parser.current_location().column,
                    "Expected ';' or '}' after expression",
                ));
            }
        } else {
            break;
        }
    }

    parser.expect(&Token::RightBrace)?;

    // Create block expression
    Ok(Some(Expression::Block(BlockExpr {
        statements,
        final_expr: result_expr.map(Box::new),
        location: parser.current_location(),
    })))
}

/// Parse if expression (Go-style with blocks)
/// Used when if appears in expression context: var x = if cond { value1 } else { value2 }
pub fn parse_if_expression(parser: &mut Parser) -> Result<Option<Expression>> {
    parser.expect(&Token::If)?;

    // Parse condition (without parentheses, Go-style)
    // We need to parse the condition but stop before the opening brace
    // Use parse_comparison to avoid parsing blocks/struct literals
    let condition = super::parse_comparison(parser)?;
    if condition.is_none() {
        return Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected condition after 'if'",
        ));
    }

    // Require opening brace (Go-style)
    if !parser.check(&Token::LeftBrace) {
        return Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected '{' after if condition in if expression",
        ));
    }

    // Parse then block as block expression
    let then_block = parse_block_expression(parser)?;
    if then_block.is_none() {
        return Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected block for if expression",
        ));
    }

    // Parse else/else if (required for if expressions to have a value)
    let else_branch = if parser.consume(&Token::Else)? {
        if parser.check(&Token::If) {
            // else if: parse as nested if expression
            parse_if_expression(parser)?
        } else if parser.check(&Token::LeftBrace) {
            // else: parse block expression
            parse_block_expression(parser)?
        } else {
            return Err(CompilerError::syntax(
                parser.current_location().line,
                parser.current_location().column,
                "Expected '{' or 'if' after 'else' in if expression",
            ));
        }
    } else {
        // If expression without else defaults to void/unit
        None
    };

    Ok(Some(Expression::If(IfExpr {
        condition: Box::new(condition.unwrap()),
        then_branch: Box::new(then_block.unwrap()),
        else_branch: else_branch.map(Box::new),
        location: parser.current_location(),
    })))
}

/// Parse for expression
pub fn parse_for_expression(parser: &mut Parser) -> Result<Option<Expression>> {
    parser.expect(&Token::For)?;

    if let Some(Token::Identifier(var_name)) = parser.peek().map(|t| &t.token) {
        let variable = var_name.clone();
        parser.advance()?;
        parser.expect(&Token::In)?;

        let iterable = super::parse_expression(parser)?;
        if iterable.is_none() {
            return Err(CompilerError::syntax(
                parser.current_location().line,
                parser.current_location().column,
                "Expected iterable after 'in'",
            ));
        }

        let body = super::parse_expression(parser)?;
        if let Some(body) = body {
            Ok(Some(Expression::For(ForExpr {
                variable,
                iterable: Box::new(iterable.unwrap()),
                body: Box::new(body),
                location: parser.current_location(),
            })))
        } else {
            Ok(None)
        }
    } else {
        Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected variable name after 'for'",
        ))
    }
}

/// Parse while expression
pub fn parse_while_expression(parser: &mut Parser) -> Result<Option<Expression>> {
    parser.expect(&Token::While)?;

    let condition = super::parse_expression(parser)?;
    if condition.is_none() {
        return Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected condition after 'while'",
        ));
    }

    let body = super::parse_expression(parser)?;
    if let Some(body) = body {
        Ok(Some(Expression::While(WhileExpr {
            condition: Box::new(condition.unwrap()),
            body: Box::new(body),
            location: parser.current_location(),
        })))
    } else {
        Ok(None)
    }
}

/// Parse panic expression (Go-style: panic(value))
pub fn parse_panic_expression(parser: &mut Parser) -> Result<Option<Expression>> {
    parser.expect(&Token::Panic)?;

    parser.expect(&Token::LeftParen)?;

    let value = super::parse_expression(parser)?;
    if value.is_none() {
        return Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected expression after 'panic('",
        ));
    }

    parser.expect(&Token::RightParen)?;

    Ok(Some(Expression::Panic(crate::ast::expr::PanicExpr {
        value: Box::new(value.unwrap()),
        location: parser.current_location(),
    })))
}

/// Parse match expression
pub fn parse_match_expression(parser: &mut Parser) -> Result<Option<Expression>> {
    parser.expect(&Token::Match)?;

    // Parse expression (optional for guard-only match)
    let expr = if parser.check(&Token::LeftBrace) {
        None
    } else {
        let expr = super::parse_expression(parser)?;
        if expr.is_none() {
            return Err(CompilerError::syntax(
                parser.current_location().line,
                parser.current_location().column,
                "Expected expression after 'match'",
            ));
        }
        expr
    };

    parser.expect(&Token::LeftBrace)?;

    let mut arms = Vec::new();

    while !parser.check(&Token::RightBrace) {
        if expr.is_some() {
            // Regular match with expression
            let pattern = parse_pattern_or(parser)?;
            if pattern.is_none() {
                break;
            }

            // Parse guard
            let guard = if parser.consume(&Token::If)? {
                super::parse_expression(parser)?
            } else {
                None
            };

            parser.expect(&Token::Arrow)?;

            let body = super::parse_expression(parser)?;
            if let (Some(pattern), Some(body)) = (pattern, body) {
                arms.push(MatchArm {
                    pattern,
                    guard,
                    body,
                    location: parser.current_location(),
                });
            }
        } else {
            // Guard-only match
            let guard = if parser.check(&Token::LeftParen) {
                parser.advance()?;
                let guard_expr = super::parse_expression(parser)?;
                parser.expect(&Token::RightParen)?;
                guard_expr
            } else if parser.check(&Token::Underscore) {
                // Handle wildcard pattern in guard-only match
                parser.advance()?;
                None // No guard for wildcard
            } else {
                super::parse_expression(parser)?
            };

            parser.expect(&Token::Arrow)?;

            let body = super::parse_expression(parser)?;
            if let Some(body) = body {
                arms.push(MatchArm {
                    pattern: Pattern::Wildcard,
                    guard,
                    body,
                    location: parser.current_location(),
                });
            }
        }

        // Check if we should continue parsing more arms
        // Continue if we find a comma or if we're at the start of a new line
        if parser.consume(&Token::Comma)? {
            continue;
        }

        // If we're at the end of the match block, break
        if parser.check(&Token::RightBrace) {
            break;
        }
    }

    parser.expect(&Token::RightBrace)?;

    Ok(Some(Expression::Match(MatchExpr {
        expr: expr
            .map(Box::new)
            .unwrap_or_else(|| Box::new(Expression::Literal(Literal::Null))),
        arms,
        location: parser.current_location(),
    })))
}

/// Parse select expression
pub fn parse_select_expression(parser: &mut Parser) -> Result<Option<Expression>> {
    parser.expect(&Token::Select)?;
    parser.expect(&Token::LeftBrace)?;

    let mut cases = Vec::new();
    let mut default_case = None;

    while !parser.check(&Token::RightBrace) {
        if parser.consume(&Token::Default)? {
            parser.expect(&Token::Arrow)?;
            default_case = super::parse_expression(parser)?;
            break;
        } else {
            let channel = super::parse_expression(parser)?;
            if channel.is_none() {
                break;
            }

            parser.expect(&Token::Arrow)?;

            let body = super::parse_expression(parser)?;
            if let Some(body) = body {
                cases.push(SelectCase {
                    channel: channel.unwrap(),
                    body,
                    location: parser.current_location(),
                });
            }
        }

        if !parser.consume(&Token::Comma)? {
            break;
        }
    }

    parser.expect(&Token::RightBrace)?;

    Ok(Some(Expression::Select(SelectExpr {
        cases,
        default_case: default_case.map(Box::new),
        location: parser.current_location(),
    })))
}

/// Parse go expression
pub fn parse_go_expression(parser: &mut Parser) -> Result<Option<Expression>> {
    parser.expect(&Token::Go)?;

    let call = super::parse_expression(parser)?;
    if let Some(Expression::Call(call_expr)) = call {
        Ok(Some(Expression::Go(GoExpr {
            call: call_expr,
            location: parser.current_location(),
        })))
    } else {
        Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected function call after 'go'",
        ))
    }
}
